package com.bionet.service_base.utils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.concurrent.*;

/**
 * @author hzx
 * @create 2021-05-12 12:46
 *
 *         String[] commands = {"cmd", "/c", "ping www.baidu.com /t"};
 *
 *         ShellUtils.run(commands,new ShellUtils.OnCommandExecOutputListener(){
 *             @Override
 *             public void onSuccess(String line) {
 *                 System.out.println(line);
 *             }
 *
 *             @Override
 *             public void onError(String line) {
 *                 System.out.println(line);
 *             }});
 **/
public final class ShellUtils {
    private static ExecutorService threadpool = Executors.newCachedThreadPool();

    private ShellUtils() {
    }

    private static Result run(boolean waitFor, String[] command, OnCommandExecOutputListener listener) {
        boolean ret = false;
        Result result = null;
        try {
            Process pid = Runtime.getRuntime().exec(command);
            Future<Result> submit = ShellUtils.threadpool.submit(new OutputHandler(pid.getInputStream(), OutputHandler.TYPE_RETRIVE_OUTPUTSTREAM, listener));
            Future<Result> submit1 = ShellUtils.threadpool.submit(new OutputHandler(pid.getErrorStream(), OutputHandler.TYPE_RETRIVE_ERRORSTREAM, listener));
            ret = (waitFor ? pid.waitFor() : pid.exitValue()) == 0;
            result = submit.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (IllegalThreadStateException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        return result;
    }

    public static Result runAsync(String[] command, OnCommandExecOutputListener listener) {
        return ShellUtils.run(false, command, listener);
    }

    public static Result run(String[] command, OnCommandExecOutputListener listener) {
        return ShellUtils.run(true, command, listener);
    }

    public interface OnCommandExecOutputListener {
        Result onSuccess(String line);

        Result onError(String line);
    }

    private static class OutputHandler implements Callable<Result> {
        private static int TYPE_RETRIVE_OUTPUTSTREAM = 0;
        private static int TYPE_RETRIVE_ERRORSTREAM = 1;
        private InputStream in;
        private OnCommandExecOutputListener listener;
        private int type;

        public OutputHandler(InputStream in, int type, OnCommandExecOutputListener listener) {
            this.in = in;
            this.type = type;
            this.listener = listener;
        }


        @Override
        public Result call() throws Exception {
            Result result = null;
            try (BufferedReader bufr = new BufferedReader(new InputStreamReader(this.in))) {
                String line = null;
                String text = "";
                while ((line = bufr.readLine()) != null) {
                    if (this.listener != null) {
                        if (this.type == OutputHandler.TYPE_RETRIVE_ERRORSTREAM) {
                            result = this.listener.onError(line);
                        } else {
                            text += line;
                        }
                    }
                }
                if (this.listener != null){
                    result = this.listener.onSuccess(text);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            return result;
        }
    }
}
